/**
 * DevOps BI 埋点脚本 - 插件化架构版
 * 
 * 使用方法:
 * <script async src="https://your-server.com/tracking/script.js" data-tracking-id="YOUR_TRACKING_ID"></script>
 * 
 * 特性:
 * - 插件化架构，低耦合高内聚
 * - 支持批量上传和单次上传
 * - 页面关闭前自动上传收集的数据
 * - 防抖和节流优化
 */
(function() {
  // 核心配置
  const core = {
    trackingId: '',
    apiUrl: '',
    sessionId: '',
    debug: false,
    
    // 插件系统
    plugins: {},
    
    // 配置参数
    config: {
      minInterval: 30000,           // 最小跟踪间隔：30秒
      maxRequestsPerMinute: 10,     // 每分钟最大请求数
      debounceDelay: 1000,          // 防抖延迟：1秒
      enableSPATracking: false,     // 默认关闭SPA路由跟踪
      batchEnabled: true,           // 默认启用批量上传
      batchSize: 10,                // 批量上传阈值
      batchInterval: 30000,         // 批量上传间隔：30秒
      criticalEvents: ['purchase', 'signup', 'login'] // 立即上传的关键事件
    },
    
    // 状态管理
    state: {
      lastTrackTime: 0,
      requestCount: 0,
      requestResetTime: Date.now(),
      isInitialized: false,
      pendingEvents: [],
      batchTimer: null
    }
  };

  // 工具函数
  const utils = {
    // 生成UUID
    generateUUID() {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
      });
    },
    
    // 序列化对象为查询字符串
    serialize(obj) {
      const str = [];
      for (const p in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, p)) {
          const value = typeof obj[p] === 'object' ? JSON.stringify(obj[p]) : obj[p];
          str.push(encodeURIComponent(p) + "=" + encodeURIComponent(value));
        }
      }
      return str.join("&");
    },
    
    // 日志函数
    log(message) {
      if (core.debug) {
        console.log('[DevOps BI]', message);
      }
    },
    
    // 防抖函数
    debounce(func, wait) {
      let timeout;
      return function() {
        const context = this;
        const args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(context, args), wait);
      };
    },
    
    // 检查是否可以跟踪（频率限制）
    canTrack() {
      const now = Date.now();
      
      // 检查最小间隔
      if (now - core.state.lastTrackTime < core.config.minInterval) {
        utils.log('跟踪频率限制：距离上次跟踪时间过短');
        return false;
      }
      
      // 检查每分钟请求数限制
      if (now - core.state.requestResetTime > 60000) {
        core.state.requestCount = 0;
        core.state.requestResetTime = now;
      }
      
      if (core.state.requestCount >= core.config.maxRequestsPerMinute) {
        utils.log('跟踪频率限制：每分钟请求数已达上限');
        return false;
      }
      
      return true;
    },
    
    // 是否为关键事件
    isCriticalEvent(eventCategory, eventAction) {
      if (!eventCategory || !eventAction) return false;
      
      const eventKey = `${eventCategory}_${eventAction}`.toLowerCase();
      return core.config.criticalEvents.some(criticalEvent => 
        eventKey.includes(criticalEvent.toLowerCase())
      );
    }
  };

  // 会话管理模块
  const sessionManager = {
    // 获取或生成会话ID
    getSessionId() {
      let id = localStorage.getItem('devops_bi_session_id');
      if (!id) {
        id = utils.generateUUID();
        localStorage.setItem('devops_bi_session_id', id);
        
        // 会话24小时后过期
        setTimeout(() => {
          localStorage.removeItem('devops_bi_session_id');
        }, 24 * 60 * 60 * 1000);
      }
      return id;
    },
    
    // 会话开始时间
    sessionStartTime: Date.now()
  };

  // 数据发送模块
  const sender = {
    // 使用图片请求发送数据
    sendViaImage(endpoint, data) {
      const img = new Image();
      const queryString = utils.serialize(data) + '&t=' + new Date().getTime();
      img.src = endpoint + '?' + queryString;
      img.style.display = 'none';
      
      img.onload = () => utils.log('数据发送成功');
      img.onerror = () => {
        utils.log('图片请求发送失败，尝试使用Fetch API');
        sender.sendViaFetch(endpoint, data);
      };
      
      document.body.appendChild(img);
    },
    
    // 使用Fetch API发送数据
    sendViaFetch(endpoint, data) {
      if (typeof fetch === 'undefined') return;
      
      fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      })
      .then(response => {
        if (response.ok) utils.log('Fetch API发送成功');
        else utils.log('Fetch API发送失败: ' + response.status);
      })
      .catch(error => utils.log('Fetch API错误: ' + error.message));
    },
    
    // 使用Beacon API发送数据（适用于页面卸载时）
    sendViaBeacon(endpoint, data) {
      if (typeof navigator.sendBeacon !== 'undefined') {
        const blob = new Blob([JSON.stringify(data)], { type: 'application/json' });
        const result = navigator.sendBeacon(endpoint, blob);
        utils.log('Beacon API发送' + (result ? '成功' : '失败'));
        return result;
      }
      
      return false;
    }
  };

  // 批量处理模块
  const batchProcessor = {
    // 添加事件到队列
    addEvent(eventData) {
      // 添加时间戳
      const event = {
        ...eventData,
        timestamp: new Date().toISOString()
      };
      
      core.state.pendingEvents.push(event);
      utils.log('事件已添加到批处理队列，当前队列长度: ' + core.state.pendingEvents.length);
      
      // 如果达到批处理阈值，触发上传
      if (core.state.pendingEvents.length >= core.config.batchSize) {
        this.flushEvents();
      }
    },
    
    // 上传所有待处理事件
    flushEvents() {
      if (core.state.pendingEvents.length === 0) return;
      
      const events = [...core.state.pendingEvents];
      core.state.pendingEvents = [];
      
      const batchData = {
        trackingId: core.trackingId,
        sessionId: core.sessionId,
        events: events,
        sessionDuration: Date.now() - sessionManager.sessionStartTime,
        url: window.location.href,
        title: document.title
      };
      
      const endpoint = core.apiUrl + 'tracking/batch';
      
      // 页面可见时使用普通请求，否则尝试使用Beacon API
      if (document.visibilityState === 'hidden') {
        if (!sender.sendViaBeacon(endpoint, batchData)) {
          sender.sendViaFetch(endpoint, batchData);
        }
      } else {
        sender.sendViaFetch(endpoint, batchData);
      }
      
      utils.log('批量上传了 ' + events.length + ' 个事件');
    },
    
    // 设置定期上传定时器
    setupBatchTimer() {
      // 清除可能存在的旧定时器
      if (core.state.batchTimer) {
        clearInterval(core.state.batchTimer);
      }
      
      // 设置新的定时器
      core.state.batchTimer = setInterval(() => {
        if (core.state.pendingEvents.length > 0) {
          this.flushEvents();
        }
      }, core.config.batchInterval);
    }
  };

  // 跟踪功能模块
  const tracker = {
    // 跟踪页面访问
    trackPageView(customData) {
      // 检查频率限制
      if (!utils.canTrack()) return;
      
      const data = {
        trackingId: core.trackingId,
        url: window.location.href,
        title: document.title,
        referrer: document.referrer,
        sessionId: core.sessionId,
        customData: customData || {
          screenWidth: window.innerWidth,
          screenHeight: window.innerHeight,
          language: navigator.language,
          timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
          timestamp: new Date().toISOString()
        }
      };
      
      utils.log('跟踪页面访问: ' + data.url);
      
      // 更新跟踪状态
      core.state.lastTrackTime = Date.now();
      core.state.requestCount++;
      
      // 根据配置决定是单次发送还是批量处理
      if (core.config.batchEnabled) {
        batchProcessor.addEvent({
          type: 'pageview',
          ...data
        });
      } else {
        const endpoint = core.apiUrl + 'tracking/pageview';
        sender.sendViaImage(endpoint, data);
      }
    },
    
    // 跟踪事件
    trackEvent(category, action, label, value, customData) {
      if (!utils.canTrack()) return;
      
      const eventData = {
        category,
        action,
        label,
        value
      };
      
      utils.log('跟踪事件: ' + category + ' / ' + action);
      
      // 构建完整数据
      const data = {
        trackingId: core.trackingId,
        url: window.location.href,
        title: document.title,
        sessionId: core.sessionId,
        customData: {
          event: eventData,
          timestamp: new Date().toISOString(),
          ...customData
        }
      };
      
      // 更新跟踪状态
      core.state.lastTrackTime = Date.now();
      core.state.requestCount++;
      
      // 关键事件立即发送，其他事件批量处理
      const isCritical = utils.isCriticalEvent(category, action);
      
      if (!core.config.batchEnabled || isCritical) {
        const endpoint = core.apiUrl + 'tracking/pageview';
        sender.sendViaImage(endpoint, data);
        utils.log('关键事件立即发送: ' + category + ' / ' + action);
      } else {
        batchProcessor.addEvent({
          type: 'event',
          category,
          action,
          label,
          value,
          ...data
        });
      }
    },
    
    // 跟踪自定义数据
    trackCustomData(customData) {
      utils.log('跟踪自定义数据');
      this.trackPageView(customData);
    }
  };

  // 插件系统
  const pluginSystem = {
    // 注册插件
    register(name, plugin) {
      if (core.plugins[name]) {
        utils.log('警告: 插件 ' + name + ' 已存在，将被覆盖');
      }
      
      core.plugins[name] = plugin;
      
      // 如果核心已初始化，则立即初始化插件
      if (core.state.isInitialized && typeof plugin.init === 'function') {
        plugin.init(core, utils);
      }
      
      utils.log('插件 ' + name + ' 已注册');
    },
    
    // 初始化所有插件
    initPlugins() {
      Object.keys(core.plugins).forEach(name => {
        const plugin = core.plugins[name];
        if (typeof plugin.init === 'function') {
          plugin.init(core, utils);
          utils.log('插件 ' + name + ' 已初始化');
        }
      });
    },
    
    // 调用所有插件的特定方法
    callMethod(methodName, ...args) {
      Object.keys(core.plugins).forEach(name => {
        const plugin = core.plugins[name];
        if (typeof plugin[methodName] === 'function') {
          plugin[methodName](...args);
        }
      });
    }
  };

  // SPA路由变化监听插件
  const spaPlugin = {
    init(core, utils) {
      if (!core.config.enableSPATracking) return;
      
      // 保存原始方法
      const originalPushState = history.pushState;
      const originalReplaceState = history.replaceState;
      
      // 重写pushState
      history.pushState = function() {
        originalPushState.apply(this, arguments);
        spaPlugin.handleUrlChange();
      };
      
      // 重写replaceState
      history.replaceState = function() {
        originalReplaceState.apply(this, arguments);
        spaPlugin.handleUrlChange();
      };
      
      // 监听popstate事件
      window.addEventListener('popstate', spaPlugin.handleUrlChange);
      
      utils.log('SPA路由监听已启用');
    },
    
    // URL变化处理
    handleUrlChange() {
      // 使用防抖版本，避免频繁跟踪
      debouncedTrackPageView();
    }
  };

  // 页面生命周期插件
  const lifecyclePlugin = {
    init() {
      // 页面可见性变化监听
      document.addEventListener('visibilitychange', this.handleVisibilityChange);
      
      // 页面卸载前处理
      window.addEventListener('beforeunload', this.handleBeforeUnload);
      
      // 页面聚焦和失焦
      window.addEventListener('focus', this.handleFocus);
      window.addEventListener('blur', this.handleBlur);
    },
    
    handleVisibilityChange() {
      const isVisible = document.visibilityState === 'visible';
      utils.log('页面可见性变化: ' + (isVisible ? '可见' : '不可见'));
      
      // 页面变为不可见时，尝试发送批量数据
      if (!isVisible && core.config.batchEnabled) {
        batchProcessor.flushEvents();
      }
    },
    
    handleBeforeUnload() {
      utils.log('页面即将卸载，发送剩余数据');
      
      // 计算会话时长
      const sessionDuration = Date.now() - sessionManager.sessionStartTime;
      
      // 添加会话结束事件
      if (core.config.batchEnabled) {
        core.state.pendingEvents.push({
          type: 'session_end',
          trackingId: core.trackingId,
          sessionId: core.sessionId,
          sessionDuration: sessionDuration,
          timestamp: new Date().toISOString()
        });
        
        // 使用Beacon API发送所有待处理事件
        batchProcessor.flushEvents();
      } else {
        // 单独发送会话结束事件
        const data = {
          trackingId: core.trackingId,
          sessionId: core.sessionId,
          customData: {
            event: {
              category: 'session',
              action: 'end',
              value: sessionDuration
            },
            timestamp: new Date().toISOString()
          }
        };
        
        const endpoint = core.apiUrl + 'tracking/pageview';
        sender.sendViaBeacon(endpoint, data);
      }
    },
    
    handleFocus() {
      utils.log('页面获得焦点');
    },
    
    handleBlur() {
      utils.log('页面失去焦点');
      
      // 页面失去焦点时，尝试发送批量数据
      if (core.config.batchEnabled) {
        batchProcessor.flushEvents();
      }
    }
  };

  // 初始化函数
  function init() {
    // 获取当前脚本标签
    const scripts = document.getElementsByTagName('script');
    const currentScript = scripts[scripts.length - 1];
    
    // 获取跟踪ID
    core.trackingId = currentScript.getAttribute('data-tracking-id');
    if (!core.trackingId) {
      utils.log('错误: 未设置 data-tracking-id 属性');
      return;
    }
    
    // 获取API URL
    core.apiUrl = currentScript.getAttribute('data-api-url');
    if (!core.apiUrl) {
      // 从脚本src中提取基础URL
      const scriptSrc = currentScript.src;
      const urlParts = scriptSrc.split('/');
      // 移除最后的 "script.js" 和 "tracking"
      urlParts.pop(); // 移除 "script.js"
      const pathSegment = urlParts.pop(); // 移除 "tracking"
      
      // 如果确实是从 /tracking/script.js 加载的
      if (pathSegment === 'tracking') {
        core.apiUrl = urlParts.join('/');
      } else {
        // 如果路径结构不同，则回退到当前域名
        core.apiUrl = window.location.origin;
        // 将移除的部分放回去
        urlParts.push(pathSegment);
        core.apiUrl = urlParts.join('/');
      }
    }
    
    // 确保apiUrl以斜杠结尾
    if (core.apiUrl && !core.apiUrl.endsWith('/')) {
      core.apiUrl += '/';
    }
    
    // 检查是否启用调试
    core.debug = currentScript.getAttribute('data-debug') === 'true';
    
    // 获取批量处理配置
    const batchEnabled = currentScript.getAttribute('data-batch-enabled');
    if (batchEnabled !== null) {
      core.config.batchEnabled = batchEnabled === 'true';
    }
    
    // 获取其他配置参数
    const configParams = [
      { attr: 'data-min-interval', config: 'minInterval', parser: parseInt },
      { attr: 'data-batch-size', config: 'batchSize', parser: parseInt },
      { attr: 'data-batch-interval', config: 'batchInterval', parser: parseInt },
      { attr: 'data-enable-spa', config: 'enableSPATracking', parser: val => val === 'true' }
    ];
    
    configParams.forEach(param => {
      const value = currentScript.getAttribute(param.attr);
      if (value !== null) {
        core.config[param.config] = param.parser(value);
      }
    });
    
    // 生成或获取会话ID
    core.sessionId = sessionManager.getSessionId();
    
    utils.log('初始化完成，跟踪ID: ' + core.trackingId);
    utils.log('API URL: ' + core.apiUrl);
    utils.log('配置: ' + JSON.stringify(core.config));
    
    // 注册内置插件
    pluginSystem.register('spa', spaPlugin);
    pluginSystem.register('lifecycle', lifecyclePlugin);
    
    // 初始化插件
    pluginSystem.initPlugins();
    
    // 设置批处理定时器
    if (core.config.batchEnabled) {
      batchProcessor.setupBatchTimer();
    }
    
    // 记录脚本加载成功
    utils.log('脚本加载成功，开始跟踪页面访问');
    
    // 只在页面首次加载时跟踪
    tracker.trackPageView();
    
    // 标记为已初始化
    core.state.isInitialized = true;
    
    // 发送脚本加载通知到服务器（可选）
    try {
      const loadData = {
        trackingId: core.trackingId,
        url: window.location.href,
        title: document.title,
        sessionId: core.sessionId,
        customData: {
          event: 'script_loaded',
          scriptVersion: '3.0.0',
          timestamp: new Date().toISOString()
        }
      };
      
      const loadEndpoint = core.apiUrl + 'tracking/script-loaded';
      sender.sendViaImage(loadEndpoint, loadData);
    } catch (e) {
      utils.log('脚本加载通知发送失败: ' + e.message);
    }
  }

  // 防抖版本的跟踪函数
  const debouncedTrackPageView = utils.debounce(tracker.trackPageView, core.config.debounceDelay);

  // 公开API
  window.DevOpsBITracker = {
    // 手动跟踪事件
    trackEvent: function(category, action, label, value, customData) {
      tracker.trackEvent(category, action, label, value, customData);
    },
    
    // 手动跟踪自定义数据
    trackCustomData: function(customData) {
      tracker.trackCustomData(customData);
    },
    
    // 手动触发批量上传
    flushEvents: function() {
      if (core.config.batchEnabled) {
        batchProcessor.flushEvents();
      }
    },
    
    // 获取配置
    getConfig: function() {
      return {
        trackingId: core.trackingId,
        sessionId: core.sessionId,
        config: core.config,
        pendingEventsCount: core.state.pendingEvents.length
      };
    },
    
    // 更新配置
    updateConfig: function(newConfig) {
      Object.assign(core.config, newConfig);
      
      // 如果批处理配置变更，重新设置定时器
      if ('batchInterval' in newConfig || 'batchEnabled' in newConfig) {
        batchProcessor.setupBatchTimer();
      }
      
      utils.log('配置已更新: ' + JSON.stringify(newConfig));
    },
    
    // 注册自定义插件
    registerPlugin: function(name, plugin) {
      pluginSystem.register(name, plugin);
    }
  };

  // 当DOM加载完成后初始化
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})(); 